package com.flyone.fuxiao.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.flyone.fuxiao.model.dto.gpt.ChatHistoryAddRequest;
import com.flyone.fuxiao.model.dto.gpt.GptAddRequest;
import com.flyone.fuxiao.model.entity.ChatHistory;
import com.flyone.fuxiao.model.entity.User;
import com.flyone.fuxiao.model.vo.*;
import com.flyone.fuxiao.service.ChatHistoryService;
import com.flyone.fuxiao.mapper.ChatHistoryMapper;
import com.flyone.fuxiao.service.UserService;
import com.flyone.fuxiao.utils.NetUtils;
import com.google.gson.Gson;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import lombok.SneakyThrows;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* @author luoyifei
*/
@Service
public class ChatHistoryServiceImpl extends ServiceImpl<ChatHistoryMapper, ChatHistory>
    implements ChatHistoryService{

    @Value("${chat-api.endpoint}")
    private String endpoint;

    @Value("${chat-api.key}")
    private String apiKey;
    @Resource
    private UserService userService;

    @SneakyThrows
    @Override
    public Flowable<String> generateTextByFlyone(GptAddRequest gptAddRequest,
                                                 HttpServletResponse response,
                                                 HttpServletRequest request) {
        Gson gson = new Gson();
        StringBuilder sb = new StringBuilder();
        String uuid = NetUtils.generateUUID();
        OkHttpClient client = new OkHttpClient();
        MediaType mediaType = MediaType.parse("application/json");
        RequestBody body = okhttp3.RequestBody.create(gson.toJson(gptAddRequest), mediaType);
        Request okRequest = new Request.Builder()
                .url(endpoint)
                .addHeader("Authorization", apiKey)
                .addHeader("Content-Type", "application/json")
                .post(body)
                .build();
        Response executeResponse = client.newCall(okRequest).execute();
        if (executeResponse.code() != 200 && (executeResponse.body() != null)) {
            throw new RuntimeException("Failed to start stream: " + executeResponse.body().string());

        }
        return Flowable.create(emitter -> {
            okhttp3.ResponseBody responseBody = executeResponse.body();
            if (responseBody == null) {
                emitter.onError(new RuntimeException("Response body is null"));
                return;
            }
            String line;
            while ((line = responseBody.source().readUtf8Line()) != null) {
                if (line.startsWith("data:")) {
                    line = line.substring(5);
                    line = line.trim();
                }
                if (Objects.equals(line, "[DONE]")) {
                    emitter.onNext(line);
                    emitter.onComplete();
                    return;
                }
                line = line.trim();
                if (line.isEmpty()) {
                    continue;
                }
                GptVO gptVO = gson.fromJson(line, GptVO.class);
                String content = gptVO.getChoices().get(0).getDelta().getContent() == null ?
                        "" : gptVO.getChoices().get(0).getDelta().getContent();
                sb.append(content);
                emitter.onNext("data: {\"id\": \"" +
                        uuid +
                        "\", \"message\": \"" +
                        content +
                        "\"}");
            }
            // 数据接收结束
            ChatHistory chatHistory = new ChatHistory();
            chatHistory.setToken(uuid);
            chatHistory.setUserId(userService.getLoginUser(request).getId());
            chatHistory.setPrompt(gptAddRequest.getMessages().get(gptAddRequest.getMessages().size() - 1).getContent());
            chatHistory.setChoice(sb.toString());
            chatHistory.setModelName(gptAddRequest.getModel());
            save(chatHistory);
            emitter.onComplete();
        }, BackpressureStrategy.BUFFER);

    }

    @Override
    public String saveChatHistory(String token, ChatHistoryAddRequest chatHistoryAddRequest, HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        ChatHistory chatHistory = new ChatHistory();
        if (StringUtils.isEmpty(token)) {
            BeanUtils.copyProperties(chatHistoryAddRequest, chatHistory);
            chatHistory.setUserId(loginUser.getId());
            token = NetUtils.generateUUID();
            chatHistory.setToken(token);
        } else {
            BeanUtils.copyProperties(chatHistoryAddRequest, chatHistory);
            chatHistory.setUserId(loginUser.getId());
            chatHistory.setToken(token);
        }
        save(chatHistory);
        return token;
    }

    @Override
    public List<ChatHistoryVO> getAllChatHistory(HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        QueryWrapper<ChatHistory> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userId",loginUser.getId());
        List<ChatHistory> chatHistoryList = list(queryWrapper);
        // 去除token重复
        Map<String, ChatHistoryVO> uniquePostHistoryMap = chatHistoryList.stream()
                .map(ChatHistoryVO::new) // 转换为 PostHistoryVO 类型
                .collect(Collectors.toMap(
                        // 键选择器，提取 token 字段作为键
                        ChatHistoryVO::getToken,
                        // 值选择器，保持不变，即 PostHistoryVO 对象本身
                        Function.identity(),
                        // 当键重复时，保留最新出现的那个对象
                        (existingValue, newValue) -> existingValue));
        return new ArrayList<>(uniquePostHistoryMap.values());
    }

    @Override
    public List<ChatHistoryRecordVO> getHistoryRecordByToken(String token, HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        QueryWrapper<ChatHistory> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userId",loginUser.getId());
        queryWrapper.eq("token",token);
        List<ChatHistory> chatHistoryList = list(queryWrapper);
        return chatHistoryList.stream().map(chatHistory -> {
            ChatHistoryRecordVO chatHistoryRecordVO = new ChatHistoryRecordVO();
            String content = chatHistory.getChoice();
            chatHistoryRecordVO.setContent(content);
            chatHistoryRecordVO.setPrompt(chatHistory.getPrompt());
            return chatHistoryRecordVO;
        }).collect(Collectors.toList());
    }

    @Override
    public String deleteHistoryRecordByToken(String token, HttpServletRequest request) {
        boolean assignUUID = this.remove(new QueryWrapper<ChatHistory>().eq("token", token));
        return assignUUID ? "success" : "fail";
    }
}




